﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using FootSteps.Data;

namespace FootSteps.Domain.Loggers.Proccess
{
    public class OpenProcessLogger : DG.Common.Patterns.MVVM.ViewModelBase
    {
        public bool Started
        {
            get { return _started; }
            set
            {
                if (value.Equals(_started)) return;
                _started = value;
                OnPropertyChanged("Started");
            }
        }

        public delegate void ProcessChangeHandler(IEnumerable<OpenProcessArgs> e);
        public event ProcessChangeHandler OnProcessChange;

        private Task _task;
        private CancellationTokenSource _cancellationToken;

        public void Start()
        {
            if (Started) return;
            Started = true;
            _cancellationToken = new CancellationTokenSource();
            _task = Task.Factory.StartNew(() =>
            {
                while (true)
                {
                    if (_cancellationToken.IsCancellationRequested)
                    {
                        return;
                    }

                    DoWork();

                    Thread.Sleep(100);
                }
            }, _cancellationToken.Token);
        }
        public void Stop()
        {
            if (!Started) return;
            Started = false;

            _cancellationToken.Cancel(false);
        }

        private IDictionary<int, Process> _lastState;
        private bool _started;

        private void DoWork()
        {
            var currentState = Process.GetProcesses().ToDictionary(p => p.Id);
            var args = new List<OpenProcessArgs>();
            var now = DateTime.Now;

            if (_lastState == null)
            {
                args.AddRange(currentState.Select(c => new OpenProcessArgs(c.Value, now, ProcessState.Opened)));
            }
            else
            {
                var removedProcess = _lastState.Where(s => !currentState.ContainsKey(s.Key)).ToArray();
                args.AddRange(removedProcess.Select(p => new OpenProcessArgs(p.Value, now, ProcessState.Closed)));

                args.AddRange(from state in currentState
                    where !_lastState.ContainsKey(state.Key)
                    select new OpenProcessArgs(state.Value, now, ProcessState.Opened));
            }
            _lastState = currentState;
            if (args.Any()) RaiseProcessChange(args.ToArray());
        }

        private void RaiseProcessChange(IEnumerable<OpenProcessArgs> args)
        {
            if (OnProcessChange != null)
                OnProcessChange(args);
        }
       
    }
}